Hello Shader之Hello Trangle

这两天配了一下现代OpenGL的开发环境,同时看了一下基础知识和编程规范

写了一个编译GLSL语言的前端程序和一个Hello trangle的程序

另外,推荐两个资源

1.学习网站Learn Opengl

2.OpenGL编程指南第八版(俗称红宝书)

网站有的地方降得不好可以看书

 

接下来总结一下知识点:

1.现代GPU内部的管线,其中蓝色部分是可编程的部分,gpu内部有许许多多的微程序,他们可以并行地执行,

可编程的微程序为蓝色部分,称为shader,即着色器程序,其中顶点着色器和片段着色器应用最多。

 

 

 

2.着色器语言GLSL的使用,着色器程序的编译,链接

  这个我专门造了一个轮子,封装了一下

#ifndef _SHADER_H_
#define _SHADER_H_

#include <GLEW/glew.h>
#include <iterator>     // std::istreambuf_iterator
#include <string>       
#include <vector>
#include <iostream>
#include <fstream>

struct ShaderFile
{
	GLenum shaderType;
	const char* filePath;
	ShaderFile(GLenum type, const char* path) 
		:shaderType(type), filePath(path){}
};

class Shader
{
public:
	Shader(const char* vertexPath, const char* fragPath) :programId(0)
	{
		std::vector<ShaderFile> fileVec;
		fileVec.push_back(ShaderFile(GL_VERTEX_SHADER, vertexPath));
		fileVec.push_back(ShaderFile(GL_FRAGMENT_SHADER, fragPath));
		loadFromFile(fileVec);
	}
	Shader(const char* vertexPath, const char* fragPath, const char* geometryPath) :programId(0)
	{
		std::vector<ShaderFile> fileVec;
		fileVec.push_back(ShaderFile(GL_VERTEX_SHADER, vertexPath));
		fileVec.push_back(ShaderFile(GL_FRAGMENT_SHADER, fragPath));
		fileVec.push_back(ShaderFile(GL_GEOMETRY_SHADER, geometryPath));
		loadFromFile(fileVec);
	}
	void use()
	{
		glUseProgram(this->programId);
	}
	~Shader()
	{
		if (this->programId)
		{
			glDeleteProgram(this->programId);
		}
	}
	GLuint GetProgramID()
	{
		return programId;
	}
public:
	GLuint programId;
private:
	/*
	* 从文件加载顶点和片元着色器
	* 传递参数为 [(着色器文件类型,着色器文件路径)+]
	*/
	void loadFromFile(std::vector<ShaderFile>& shaderFileVec)
	{
		std::vector<GLuint> shaderObjectIdVec;
		std::string vertexSource, fragSource;
		std::vector<std::string> sourceVec;
		size_t shaderCount = shaderFileVec.size();
		// 读取文件源代码
		for (size_t i = 0; i < shaderCount; ++i)
		{
			std::string shaderSource;
			if (!loadShaderSource(shaderFileVec[i].filePath, shaderSource))
			{
				std::cout << "Error::Shader could not load file:" << shaderFileVec[i].filePath << std::endl;
				return;
			}
			sourceVec.push_back(shaderSource);
		}
		bool bSuccess = true;
		// 编译shader object
		for (size_t i = 0; i < shaderCount; ++i)
		{
			GLuint shaderId = glCreateShader(shaderFileVec[i].shaderType);
			const char *c_str = sourceVec[i].c_str();
			glShaderSource(shaderId, 1, &c_str, NULL);
			glCompileShader(shaderId);
			GLint compileStatus = 0;
			glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compileStatus); // 检查编译状态
			if (compileStatus == GL_FALSE) // 获取错误报告
			{
				GLint maxLength = 0;
				glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength);
				std::vector<GLchar> errLog(maxLength);
				glGetShaderInfoLog(shaderId, maxLength, &maxLength, &errLog[0]);
				std::cout << "Error::Shader file [" << shaderFileVec[i].filePath << " ] compiled failed,"
						  << &errLog[0] << std::endl;
				bSuccess = false;
			}
			shaderObjectIdVec.push_back(shaderId);
		}
		// 链接shader program
		if (bSuccess)
		{
			this->programId = glCreateProgram();
			for (size_t i = 0; i < shaderCount; ++i)
			{
				glAttachShader(this->programId, shaderObjectIdVec[i]);
			}
			glLinkProgram(this->programId);
			GLint linkStatus;
			glGetProgramiv(this->programId, GL_LINK_STATUS, &linkStatus);
			if (linkStatus == GL_FALSE)
			{
				GLint maxLength = 0;
				glGetProgramiv(this->programId, GL_INFO_LOG_LENGTH, &maxLength);
				std::vector<GLchar> errLog(maxLength);
				glGetProgramInfoLog(this->programId, maxLength, &maxLength, &errLog[0]);
				std::cout << "Error::shader link failed," << &errLog[0] << std::endl;
			}
		}
		// 链接完成后detach 并释放shader object
		for (size_t i = 0; i < shaderCount; ++i)
		{
			if (this->programId != 0)
			{
				glDetachShader(this->programId, shaderObjectIdVec[i]);
			}
			glDeleteShader(shaderObjectIdVec[i]);
		}
	}
	/*
	* 读取着色器程序源码
	*/
	bool loadShaderSource(const char* filePath,std::string& source)
	{
		source.clear();
		std::ifstream in_stream(filePath);
		if (!in_stream)
		{
			return false;
		}
		source.assign(std::istreambuf_iterator<char>(in_stream),
			std::istreambuf_iterator<char>()); // 文件流迭代器构造字符串
		return true;
	}
};
#endif

  

3.关于VBO和VAO

这两个的使用函数等等我就不搬上来了,没什么意义

只解释下两者的实质和容易出错的地方

VBO译名顶点缓冲对象,用来从CPU内存读取数据到GPU内存(以后称作显存)中,VBO的内存是独立的,真正存在的,同时一个VBO只能存一段内存

VAO称为顶点数组对象,用来负责组织,解释VBO,记录渲染环境,VAO并不是占有独立内存,仅仅相当于做个索引的作用,可以想象成指针,也就是说VAO是依托于VBO存在的,一旦VBO改变了,VAO也就改变了

 

 

最后,鹅厂的面试经历和个人这一段时间和大学生活的总结展望在论坛上开了个坑,最近踪迹应该在论坛上:

传送门:

腾讯实习生面试经历(不打算一次写完,开个坑,慢慢更,同时也算是帮助自己思考些未来)

posted @ 2017-04-26 12:24  LT.C#  阅读(340)  评论(0编辑  收藏  举报