OpenGL学習記録(3)

参考文献:
https://learnopengl.com/
https://learnopengl-cn.github.io/

今回、Shader シェーダ クラスが実装され、文字列形式で記述された頂点およびフラグメント シェーダ コードを .txt ファイルを通じて読み込むことができ、シェーダのコンパイルとリンクの処理がシェーダ クラスに移動されます。メインプログラムのコードがもう少し簡潔になります。

まず、glShaderSource 関数は、変更されない const char* 型を受け取ります。このような型を取得するには、.txt ファイルのバッファリングされたコンテンツをデータ ストリームに読み取り、データ ストリームを String に変換する必要があります。最後に .c_str () メソッドを渡すと、 const char* に変換されます。

先ほどのmain関数での頂点/フラグメントシェーダの定義、作成、アタッチ、コンパイルという一連の処理と、プログラムオブジェクトの作成、このオブジェクトへのシェーダのアタッチ、リンク処理をShaderクラスで実装することができ、 main関数のコード量を最適化します。

また、エラー情報を出力するメソッドも実装されており、glGetShaderiv と glGetProgramiv を使用してシェーダが正常にコンパイルおよびリンクされたかどうかを確認し、int 型の成功を参照として渡し、返される結果は次のようになります。 success に渡され、success の値に応じてエラーがあるかどうかを判断し、エラーがある場合はそれぞれ glGetShaderInfoLog と glGetProgramInfoLog を呼び出し、文字配列を渡して情報を受け取り、 cout を使用して情報を出力します。

シェーダ クラスが確立された後、const char* で表される元のシェーダ コードをそれぞれの .txt ファイルに移動でき、変更がより便利になります。このクラスを main 関数で使用する場合、新しい Shader クラス オブジェクトを作成し、頂点シェーダーとフラグメント シェーダーのファイル名を渡すだけで済みます。ループ レンダリング段階では、シェーダオブジェクト。

.h:

#pragma once
#include <string>

class Shader
{
    
    
public:
	Shader(const char* vertexPath, const char* fragmentPath);
	
	//读取文件的缓冲内容到数据流中->数据流转换到String->String转换到const char*
	//String用作中转
	std::string vertexString;
	std::string fragmentString;
	
	//着色器最终需要的是const char*
	const char* vertexSource;
	const char* fragmentSource;

	unsigned int ID; //程序ID

	void use(); //glUseProgram激活程序

private:
	void checkCompileErrors(unsigned int ID, std::string type);
};

.cpp:

#include "Shader.h"
#include <fstream>
#include <sstream>

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
    
    
	//从文件路径中获取顶点/片段着色器
	std::ifstream vertexFile;
	std::ifstream fragmentFile;
	std::stringstream vertexSStream;
	std::stringstream fragmentSStream;

	vertexFile.open(vertexPath); //打开文件
	fragmentFile.open(fragmentPath);
	vertexFile.exceptions(std::ifstream::failbit || std::ifstream::badbit); //保证ifstream对象可以抛出异常
	fragmentFile.exceptions(std::ifstream::failbit || std::ifstream::badbit);

	try
	{
    
    
		if (!vertexFile.is_open() || !fragmentFile.is_open())
		{
    
    
			throw std::exception("open file error."); //打开失败抛出异常
		}
		vertexSStream << vertexFile.rdbuf(); //读取文件的缓冲内容到数据流中
		fragmentSStream << fragmentFile.rdbuf();

		vertexString = vertexSStream.str(); //数据流转换到String
		fragmentString = fragmentSStream.str();

		vertexSource = vertexString.c_str(); //String转换到const char*
		fragmentSource = fragmentString.c_str();

		unsigned int vertex, fragment; //声明顶点/片元着色器

		//编译顶点着色器
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vertexSource, nullptr);
		glCompileShader(vertex);
		checkCompileErrors(vertex, "VERTEX"); //检查错误

		//编译片元着色器
		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment, 1, &fragmentSource, nullptr);
		glCompileShader(fragment);
		checkCompileErrors(fragment, "FRAGMENT"); //检查错误

		//创建、链接着色器程序对象
		ID = glCreateProgram();
		glAttachShader(ID, vertex);
		glAttachShader(ID, fragment);
		glLinkProgram(ID);
		checkCompileErrors(ID, "PROGRAM"); //检查错误

		glDeleteShader(vertex); //着色器已经链接到程序中了,不再需要所以删除
		glDeleteShader(fragment);
	}
	catch (const std::exception& ex)
	{
    
    
		printf(ex.what());
	}
}

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

//打印错误
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, nullptr, infoLog);
			std::cout << "Shader compile error: " << infoLog << std::endl; //打印编译错误
		}
	}
	else
	{
    
    
		glGetProgramiv(ID, GL_LINK_STATUS, &success);
		if (!success)
		{
    
    
			glGetProgramInfoLog(ID, 512, nullptr, infoLog);
			std::cout << "Program link error: " << infoLog << std::endl; //打印链接错误
		}
	}
}

おすすめ

転載: blog.csdn.net/weixin_47260762/article/details/128191728