学了接近一个月的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()设置好参数就可以了。