Hello Shader之Hello Trangle

這兩天配了一下現代OpenGL的開發環境,同時看了一下基礎知識和編程規範前端

寫了一個編譯GLSL語言的前端程序和一個Hello trangle的程序ios

另外,推薦兩個資源面試

1.學習網站Learn Opengl編程

2.OpenGL編程指南第八版(俗稱紅寶書)數組

網站有的地方降得很差能夠看書函數

 

接下來總結一下知識點:學習

1.現代GPU內部的管線,其中藍色部分是可編程的部分,gpu內部有許許多多的微程序,他們能夠並行地執行,網站

可編程的微程序爲藍色部分,稱爲shader,即着色器程序,其中頂點着色器和片斷着色器應用最多。ui

 

 

 

2.着色器語言GLSL的使用,着色器程序的編譯,連接this

  這個我專門造了一個輪子,封裝了一下

#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也就改變了

 

 

最後,鵝廠的面試經歷和我的這一段時間和大學生活的總結展望在論壇上開了個坑,最近蹤影應該在論壇上:

傳送門:

騰訊實習生面試經歷(不打算一次寫完,開個坑,慢慢更,同時也算是幫助本身思考些將來)

相關文章
相關標籤/搜索