OpenGL中shader使用



       學了接近一個月的OpenGL,最終要排上用場了...好吧,就從學到的shader(着色器)開刀吧。

       先簡單的介紹shader,shader事實上是顯卡的功能,就是利用顯卡的GPU去做圖像處理的工作,而不是CPU,這樣能夠在一些復雜的大程序中釋放CPU空間而提高效率。這篇文章僅僅是簡單的介紹shader的使用,並沒有介紹着色語言的語法結構等方面內容。后面等自己研究好了繼續更新。

       使用shader,一般要經過一下幾個步驟:

1、創建shader,這里會使用到glew的拓展庫,應該包括glew.h和glew32.lib。利用一下函數創建:

GLhandleARB frag_shader;
//創建fragment Shader
//--------------------------------------------------------------------
// GLuint glCreateShader(GLenum shaderType);  
// 參數:  
// ·shaderType – GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.  
//--------------------------------------------------------------------
frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);


2、向shader中導入着色程序,利用一下函數:

//---------------------------------------------------------------------------------------------------------------------
//void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);  
//參數:  
//·shader – the handler to the shader.  
//·numOfStrings – the number of strings in the array.  
//·strings – the array of strings.  
//·lenOfStrings – an array with the length of each string, or NULL, meaning that the strings are NULL terminated. 
//----------------------------------------------------------------------------------------------------------------------
glShaderSourceARB(frag_shader,1,(const char**)&inShader,NULL);

3、編譯shader,就是將着色程序編譯成shader能夠識別的程序,以便使用:

//---------------------------------------------------------
//void glCompileShader(GLuint shader);  
//參數:  
//.shader – the handler to the shader.  
//----------------------------------------------------------
glCompileShaderARB(frag_shader);

4、查詢shader的狀態,shader並不能向C/C++編譯器那樣能夠print信息出來以參考,可是能夠通過logInfo來看:

glGetObjectParameterivARB(frag_shader,GL_OBJECT_COMPILE_STATUS_ARB,&result);

if(!result)
{
	char str[4096] = {0};
	//------------------------------------------------------------------------------------
	//將調試信息放入infoLog中
	//void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log);
	//void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);
	//參數:
	//·object – the handler to the object. Either a shader or a program
	//·maxLen – The maximum number of chars to retrieve from the InfoLog.
	//·len – returns the actual length of the retrieved InfoLog.
	//·log – The log itself.
	//------------------------------------------------------------------------------
	glGetInfoLogARB(frag_shader,sizeof(str),NULL,str);
	glDeleteObjectARB(frag_shader);
	return ;
}

5、連接shader,前面僅僅是把着色程序編譯OK,如今要給創建好的shader使用:

shader = link(1,frag_shader);

6、link()函數是我自己寫的,以下是link函數的代碼:

GLhandleARB CShader::link(int shader_count,...)
{
	//創建一個程序
	GLhandleARB program = glCreateProgramObjectARB();
	GLhandleARB shaderT = NULL;

	va_list marker;

	//初始化
	va_start(marker,shader_count);
	for(int i = 0; i< shader_count; i++)
	{
		shaderT = va_arg(marker,GLhandleARB);
		//------------------------------------------------------------
		//void glAttachShader(GLuint program, GLuint shader);  
		//參數:  
		//	·program – the handler to the program.  
		//	·shader – the handler to the shader you want to attach.  
		//-------------------------------------------------------------
		glAttachObjectARB(program,shaderT);
	}
	va_end(marker);

	//連接程序
	glLinkProgramARB(program);

	int result = 0;
	glGetObjectParameterivARB(program,GL_OBJECT_LINK_STATUS_ARB,&result);
	if(!result)
	{
		char str[4096] = {0};
		glGetInfoLogARB(program,sizeof(str),NULL,str);
		glDeleteObjectARB(program);

		return NULL;
	}
	return program;
}

事實上這個函數能夠將多個着色程序給一個shader使用。

7、后面就是怎么使用Shader了,使用glUseProgram(program)和glUseProgram(NULL)要使用和卸載shader,

     還有能夠從C++代碼中傳遞給着色程序的參數。

8、還有就是怎么把着色程序導入到shader中,這里事實上是一個純讀取文檔的過程,並不難。

這里給出整個shader的程序:

CShader.h

#pragma once 

#ifndef GL_ARB_shader_objects
typedef GLhandleARB
typedef GLcharARB
#endif

class CShader
{
public:
	CShader(void);
public:
	~CShader(void);

public:
	//初始化shader
	void init(const char* inShader);

	//綁定紋理
	void bind();

	//撤銷紋理
	void unBind();

	bool setParameter(char* keyword, GLfloat fv);
	bool setParameter(char* keyword, GLuint texID);
	char* loadShaderTex(const char* fileName);


private:
	GLhandleARB link(int shader_count,...);
public:
	GLhandleARB shader;

};


CShader.cpp

#include "stdafx.h"
#include <gl/glew.h>
#include "CShader.h"
#include <stdlib.h>
#include <stdarg.h>

#pragma comment(lib,"glew32.lib")

CShader::CShader(void)
{

}

CShader::~CShader(void)
{

}

void CShader::init(const char* inShader)
{
	GLhandleARB frag_shader;
	//創建fragment Shader
	//--------------------------------------------------------------------
	// GLuint glCreateShader(GLenum shaderType);  
	// 參數:  
	// ·shaderType – GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.  
	//--------------------------------------------------------------------
	frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);

	//---------------------------------------------------------------------------------------------------------------------
	//void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);  
	//參數:  
	//	·shader – the handler to the shader.  
	//	·numOfStrings – the number of strings in the array.  
	//	·strings – the array of strings.  
	//	·lenOfStrings – an array with the length of each string, or NULL, meaning that the strings are NULL terminated. 
	//----------------------------------------------------------------------------------------------------------------------
	glShaderSourceARB(frag_shader,1,(const char**)&inShader,NULL);
	
	//---------------------------------------------------------
	//void glCompileShader(GLuint shader);  
	//參數:  
	//	.shader – the handler to the shader.  
	//----------------------------------------------------------
	glCompileShaderARB(frag_shader);

	int result = 0;
	//查詢狀態
	glGetObjectParameterivARB(frag_shader,GL_OBJECT_COMPILE_STATUS_ARB,&result);

	if(!result)
	{
		char str[4096] = {0};
		//------------------------------------------------------------------------------------
		//將調試信息放入infoLog中
		//void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log);
		//void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);
		//參數:
		//	·object – the handler to the object. Either a shader or a program
		//	·maxLen – The maximum number of chars to retrieve from the InfoLog.
		//	·len – returns the actual length of the retrieved InfoLog.
		//	·log – The log itself.
		//------------------------------------------------------------------------------
		glGetInfoLogARB(frag_shader,sizeof(str),NULL,str);
		glDeleteObjectARB(frag_shader);
		return ;
	}
	//Compile shader
	shader = link(1,frag_shader);
	glDeleteObjectARB(frag_shader);
}

GLhandleARB CShader::link(int shader_count,...)
{
	//創建一個程序
	GLhandleARB program = glCreateProgramObjectARB();
	GLhandleARB shaderT = NULL;

	va_list marker;

	//初始化
	va_start(marker,shader_count);
	for(int i = 0; i< shader_count; i++)
	{
		shaderT = va_arg(marker,GLhandleARB);
		//------------------------------------------------------------
		//void glAttachShader(GLuint program, GLuint shader);  
		//參數:  
		//	·program – the handler to the program.  
		//	·shader – the handler to the shader you want to attach.  
		//-------------------------------------------------------------
		glAttachObjectARB(program,shaderT);
	}
	va_end(marker);

	//連接程序
	glLinkProgramARB(program);

	int result = 0;
	glGetObjectParameterivARB(program,GL_OBJECT_LINK_STATUS_ARB,&result);
	if(!result)
	{
		char str[4096] = {0};
		glGetInfoLogARB(program,sizeof(str),NULL,str);
		glDeleteObjectARB(program);

		return NULL;
	}
	return program;
}

void CShader::bind()
{
	//if shader link successfully,then use it
	glUseProgram( shader);	
}
bool CShader::setParameter(char* keyword,GLfloat fv)
{
	//find out where the flicker constant lives
	GLint ret = glGetUniformLocation(shader, keyword);
	if(ret != -1)
	{
		glUniform1f(ret,fv);
		return true;
	}
	return false;
}

bool CShader::setParameter(char* keyword,GLuint texID)
{
	//Find out where the flicker constant lives
	GLint ret = glGetUniformLocation(shader,keyword);

	if(ret != -1)
	{
		glUniform1iARB(ret, texID);
		return true;
	}
	return false;
}

void CShader::unBind()
{
	glUseProgramObjectARB(NULL);
}

char* CShader::loadShaderTex(const char* fileName)
{
	char* shaderText = NULL;
	GLint shaderLength = 0;
	FILE *fp;

	fp = fopen(fileName,"r");
	if(fp != NULL)
	{
		//get the char length 
		while(fgetc(fp) != EOF)
		{
			shaderLength++;
		}
		rewind(fp);

		shaderText = (GLchar*)malloc(shaderLength);
		if(shaderText != NULL)
		{
			fread(shaderText,1,shaderLength,fp);
		}
		shaderText[shaderLength] = '\0';
		fclose(fp);
	}
	return shaderText;
}

上面有把shader僅僅用寫成接口,並沒有給出着色程序的代碼,你須要將着色程序保存為文本文檔,然后用loadShaderText()讀取程序,然后就是init(),利用setParameter()設置好參數就能夠了。




 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM