OpenGL超级宝典 渲染管线(三)

片段着色器

片段着色器是负责确定各片段的颜色,然后将片段发送到帧缓冲,以便合成到窗口。
就是在这个阶段确定模型的颜色

自己封装的Shader类(改进中…)

Shader.h

#pragma once
#include "sb7.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <exception>
class Shader
{
public:
	Shader();
	Shader(const std::string vertexPath, const std::string fragmentPath);
	Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath);

	//设置顶点着色器
	void setVertexShder(const std::string vertexPath);
	//设置曲面细分控制着色器
	void setTescShader(const std::string tescPath);
	//设置曲面细分评估着色器
	void setTeseShader(const std::string tesePath);
	//设置片段着色器
	void setFragmentShader(const std::string fragmentPath);

	//program对象使用
	void use();
private:
	GLuint program;

	//源代码
	std::string shaderString;
	const char* shaderSource;
	//用于读取shader文件
	std::ifstream shaderFile;
	//转换源码
	std::stringstream shaderSStream;

private:
	//查错程序,是否有编译错误
	void checkCompileErrors(unsigned int ID, std::string type);
	//读取文件,并且创建着色器对象
	void readShaderSource(std::string shaderFilePath);
	//链接着色器
	void linkShader(GLuint shaderObject);
};

Shader.cpp

#include "Shader.h"

Shader::Shader(){}

Shader::Shader(const std::string vertexPath, const std::string fragmentPath)
{
	//创建程序对象
	program = glCreateProgram();

	setVertexShder(vertexPath);
	setFragmentShader(fragmentPath);
	
}

Shader::Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath)
{
	//创建程序对象
	program = glCreateProgram();

	setVertexShder(vertexPath);
	setFragmentShader(fragmentPath);
	setTescShader(tescPath);
	setTeseShader(tesePath);
}

//设置顶点着色器
void Shader::setVertexShder(const std::string vertexPath)
{
	//读取shader源代码
	readShaderSource(vertexPath);
	//创建shader对象
	GLuint vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	//链接shader对象
	linkShader(vertexShader);
}

//设置曲面细分控制着色器
void Shader::setTescShader(const std::string tescPath)
{
	//读取shader源代码
	readShaderSource(tescPath);
	//创建shader对象
	GLuint tescShader;
	tescShader = glCreateShader(GL_TESS_CONTROL_SHADER);
	//链接shader对象
	linkShader(tescShader);
}

//设置曲面细分评估着色器
void Shader::setTeseShader(const std::string tesePath)
{
	//读取shader源代码
	readShaderSource(tesePath);
	//创建shader对象
	GLuint teseShader;
	teseShader = glCreateShader(GL_TESS_EVALUATION_SHADER);
	//链接shader对象
	linkShader(teseShader);
}

//设置片段着色器
void Shader::setFragmentShader(const std::string fragmentPath)
{
	//读取shader源代码
	readShaderSource(fragmentPath);
	//创建shader对象
	GLuint fragmentShader;
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	//链接shader对象
	linkShader(fragmentShader);
}

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

//读取文件,并且创建着色器对象
void Shader::readShaderSource(std::string shaderFilePath)
{
	//将上一个shader的源码清理
	shaderSStream.str("");
	memset(&shaderSource, '\0', sizeof(shaderSource));
	//open shader file
	if (!shaderFilePath.empty())	//判断文件路径是否为空
	{
		
		//文件路径不为空,打开文件
		shaderFile.open(shaderFilePath);
		shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);

		try
		{
			if (!shaderFile.is_open())	//文件打开失败
			{
				throw std::exception("open fragment shader file fail");
			}
			//文件成功打开
			//字符串流读取文件中的数据
			shaderSStream << shaderFile.rdbuf();
			//读完了,把文件关了
			shaderFile.close();
			//把源代码读入字符串中去
			shaderString = shaderSStream.str();
			//把string转成系数需要的const char *类型
			shaderSource = shaderString.c_str();
			
		}
		catch (const std::exception& e)
		{
			std::cout << e.what() << std::endl;
		}
	}
}

//链接着色器
void Shader::linkShader(GLuint shaderObject)
{
	//将源代码读入shader对象
	glShaderSource(shaderObject, 1, &shaderSource, NULL);
	//编译shader对象中的源码
	glCompileShader(shaderObject);
	//将shader对象附加到program对象上去
	glAttachShader(program, shaderObject);
	//链接program对象上的shader对象
	glLinkProgram(program);
	//查错
	checkCompileErrors(program, "PROGRAM");
	//完事,可以把shader对象删了
	glDeleteShader(shaderObject);
}


/*
* 查错
*/
void Shader::checkCompileErrors(unsigned int ID, std::string type)
{
	int success;
	char infoLog[512];

	if (type != "PROGRAM")
	{
		glGetShaderiv(ID, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(ID, 512, NULL, infoLog);
			std::cout << "shader compile error: " << infoLog << std::endl;
		}
	}
	else
	{
		glGetProgramiv(ID, GL_LINK_STATUS, &success);
		if (!success)
		{
			glGetProgramInfoLog(ID, 512, NULL, infoLog);
			std::cout << "program linking error: " << infoLog << std::endl;
		}
	}
}

shader file

vertex shader

#version 450 core
layout(location = 0) in vec4 offset;

//输出颜色到下一个着色器
out vec4 vs_color;

void main()
{
	const vec4 vertices[] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),
	vec4(-0.25, -0.25, 0.5, 1.0),
	vec4(0.25, 0.25, 0.5, 1.0));

	const vec4 colors[] = vec4[3](vec4(1.0, 0.0, 0.0, 1.0),
	vec4(0.0, 1.0, 0.0, 1.0),
	vec4(0.0, 0.0, 1.0, 1.0));

	gl_Position = vertices[gl_VertexID];
	//输出到下一个阶段
	vs_color = colors[gl_VertexID];
}

fragment shader

#version 450 core

//接收上一个着色器的输出
in vec4 vs_color;
//将颜色输出到屏幕或者窗口
out vec4 color;

void main()
{
	color = vs_color;	
}

代码

#include "sb7.h"
#include "Shader.h"
#include <math.h>

class my_appliciation : public sb7::application
{
public:
	void startup()
	{
		shader = new Shader("vertexShader.vert", "fragmentShader.frag");

		//创建vao对象
		glCreateVertexArrays(1, &vertex_array_object);
		//将vao对象绑定到上下文
		glBindVertexArray(vertex_array_object);
	}

	void render(double currentTime)
	{
		GLfloat attrib[] = { (float)sin(currentTime) * 0.5f + 0.5,
		(float)cos(currentTime) * 0.6f + 0.5, 0, 0 };

		shader->use();

		//将数据绑定到vao的第0个位置,就是vertex shader里面location = 0的位置
		glVertexAttrib4fv(0, attrib);
		//绘制图形
		glDrawArrays(GL_TRIANGLES, 0, 3);
	}

	void shutdown()
	{

	}

private:
	//shader对象
	Shader* shader;
	//vao
	GLuint vertex_array_object;
};

DECLARE_MAIN(my_appliciation);

效果在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ht巷子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值