學了接近一個月的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()設置好參數就能夠了。