Learn OpenGL(五)——定义自己的着色器

定义自己的着色器


       编写、编译、管理着色器是件麻烦事。在着色器的最后主题里,我们会写一个类来让我们的生活轻松一点,这个类从硬盘读着色器,然后编译和链接它们,对它们进行错误检测,这就变得很好用了。这也会给你一些关于如何把我们目前所学的知识封装到一个抽象的对象里的灵感。
       我们会在头文件里创建整个类,主要为了学习,也可以方便移植。我们先来添加必要的include,定义类结构:

#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
#include <GL/glew.h>; // 包含glew获取所有的OpenGL必要headers
class Shader
{
public:
// 程序ID
GLuint Program;
// 构造器读取并创建Shader
Shader(const GLchar * vertexSourcePath, const GLchar * fragmentSourcePath);
// 使用Program
void Use();
};
#endif

 


注:
在上面,我们用了几个预处理指令(Preprocessor Directives)。这些预处理指令告知你的编译器,只在没被包
含过的情况下才包含和编译这个头文件,即使多个文件都包含了这个shader头文件,它是用来防止链接冲突的。
     

        shader类保留了着色器程序的ID。它的构造器需要顶点和片段着色器源代码的文件路径,我们可以把各自的文本文件储存在硬盘上。 Use 函数看似平常,但是能够显示这个自造类如何让我们的生活变轻松(虽然只有一点)。


从文件读取


       我们使用C++文件流读取着色器内容,储存到几个string对象里着色器
 

Shader(const GLchar * vertexPath, const GLchar * fragmentPath)
{
// 1. 从文件路径获得vertex/fragment源码
std::string vertexCode;
std::string fragmentCode;
try {
// 打开文件
std::ifstream vShaderFile(vertexPath);
std::ifstream fShaderFile(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// 读取文件缓冲到流
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件句柄
vShaderFile.close();
fShaderFile.close();
// 将流转为GLchar数组
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch(std::exception e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}


     下一步,我们需要编译和链接着色器。注意,我们也要检查编译/链接是否失败,如果失败,打印编译错误,调试的时候这及其重要(这些错误日志你总会需要的):

着色器
 

// 2. 编译着色器
GLuint vertex, fragment;
GLint success;
GLchar 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);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl
;
};
// 对片段着色器进行类似处理
[...]
// 着色器程序
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
// 打印连接错误
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 删除着色器
glDeleteShader(vertex);
glDeleteShader(fragment);

    最后我们也要实现Use函数:

void Use()
{
glUseProgram(this->Program);
}


     现在我们写完了一个完整的着色器类。使用着色器类很简单;我们创建一个着色器对象以
后,就可以简单的使用了:
着色器

Shader ourShader("path/to/shaders/shader.vs", "path/to/shaders/shader.frag");
...
while(...)
{
ourShader.Use();
glUniform1f(glGetUniformLocation(ourShader.Program, "someUniform"), 1.0f);
DrawStuff();
}



      我们把顶点和片段着色器储存为两个叫做 shader.vs 和 shader.frag 的文件。你可以使用自己喜欢的名字命名着色器文件;我自己觉得用 .vs 和 .frag 作为扩展名很直观。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值