拿出来直接运行即可,可以直接理解什么是GLSL,之所以贴出来是因为很多文章写得乱七八糟,一面解释,一面贴代码,有必要吗??很多GLSL电子书都有很详细的解释的。
我的OpenGL框架代码可能和你的框架的有些不同,可以把init、update、draw实现拿出来即可。
vertexshader.txt
varying vec4 color;
void main()
{
//gl_FragColor是输出片段颜色的内建变量,凡是以gl_开头的变量都是内建变量
gl_FragColor = color;
uniform vec3 lightposition;//光源位置
uniform vec3 eyeposition;//相机位置
uniform vec4 ambient;//环境光颜色
uniform vec4 lightcolor;//光源颜色
uniform float Ns;//高光系数
uniform float attenuation;//光线的衰减系数
varying vec4 color;//向片段着色其传递的参数
void main()
{
/*很多示例中都是利用uniform参数从应用程序中向shader里传递当前模型视图矩阵和模型视图投影矩阵,其实对于初学者来说,我们大可以先用GLSL的内建变量:gl_ModelViewMatrix和gl_ModelViewProjectionMatrix代替,而顶点坐标的变换则直接可以利用内建函数ftransform()实现。当然,如果你想自己传递这些参数也是可以的,后面会介绍一下。而gl_Vertex和gl_Normal则分别表示当前传入的顶点的物体坐标系坐标和表面法向量,gl_Position则是用来传输投影坐标系内顶点坐标的内建变量。注意内建变量是不用声明的,直接使用就行*/
vec3 ECPosition = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 N = normalize(gl_NormalMatrix * gl_Normal);
vec3 L = normalize(lightposition - ECPosition);
vec3 V = normalize(eyeposition - ECPosition);
vec3 H = normalize(V + L);
vec3 diffuse = lightcolor * max(dot(N , L) , 0);
vec3 specular = lightcolor * pow(max(dot(N , H) , 0) , Ns) * attenuation;
color = vec4(clamp((diffuse + specular) , 0.0 , 1.0) , 1.0);
color = color + ambient;
gl_Position = ftransform();
}
uniform vec3 eyeposition;//相机位置
uniform vec4 ambient;//环境光颜色
uniform vec4 lightcolor;//光源颜色
uniform float Ns;//高光系数
uniform float attenuation;//光线的衰减系数
varying vec4 color;//向片段着色其传递的参数
void main()
{
/*很多示例中都是利用uniform参数从应用程序中向shader里传递当前模型视图矩阵和模型视图投影矩阵,其实对于初学者来说,我们大可以先用GLSL的内建变量:gl_ModelViewMatrix和gl_ModelViewProjectionMatrix代替,而顶点坐标的变换则直接可以利用内建函数ftransform()实现。当然,如果你想自己传递这些参数也是可以的,后面会介绍一下。而gl_Vertex和gl_Normal则分别表示当前传入的顶点的物体坐标系坐标和表面法向量,gl_Position则是用来传输投影坐标系内顶点坐标的内建变量。注意内建变量是不用声明的,直接使用就行*/
vec3 ECPosition = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 N = normalize(gl_NormalMatrix * gl_Normal);
vec3 L = normalize(lightposition - ECPosition);
vec3 V = normalize(eyeposition - ECPosition);
vec3 H = normalize(V + L);
vec3 diffuse = lightcolor * max(dot(N , L) , 0);
vec3 specular = lightcolor * pow(max(dot(N , H) , 0) , Ns) * attenuation;
color = vec4(clamp((diffuse + specular) , 0.0 , 1.0) , 1.0);
color = color + ambient;
gl_Position = ftransform();
}
fragmentshader.txt
//这里的的varying变量名称要与顶点着色器里的一样,否则会编译错误
varying vec4 color;
void main()
{
//gl_FragColor是输出片段颜色的内建变量,凡是以gl_开头的变量都是内建变量
gl_FragColor = color;
}
OpenGL代码:
头文件如下:
#pragma once
#include "GLFrame.h"
#include <gl\glew.h>
#include <gl\gl.h>
#include <gl\GLUT.H>
#include <cmath>
#include <iostream>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"glut32.lib")
#pragma comment(lib,"glaux.lib")
#pragma comment(lib,"glew32.lib")
class CGraphics:GLApplication
{
public:
~CGraphics(void);
bool Init();
void Update(DWORD milliseconds);
void Uninit();
void Draw();
CGraphics(const char * class_name, const char* form_title);
GLchar* readShaderSource(const char* filename);
int installShaders(const GLchar *Vertex,const GLchar *Fragment);
float m_angle;
private:
friend class GLApplication;
};
#include "GLFrame.h"
#include <gl\glew.h>
#include <gl\gl.h>
#include <gl\GLUT.H>
#include <cmath>
#include <iostream>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"glut32.lib")
#pragma comment(lib,"glaux.lib")
#pragma comment(lib,"glew32.lib")
class CGraphics:GLApplication
{
public:
~CGraphics(void);
bool Init();
void Update(DWORD milliseconds);
void Uninit();
void Draw();
CGraphics(const char * class_name, const char* form_title);
GLchar* readShaderSource(const char* filename);
int installShaders(const GLchar *Vertex,const GLchar *Fragment);
float m_angle;
private:
friend class GLApplication;
};
实现文件.cpp:
#include "Graphics.h"
#include <gl\gl.h> /**< 包含OpenGL头文件 */
#include <gl\glu.h>
#include <gl\glaux.h>
GLfloat ambient[4] = {1.0 , 0.0 , 0.0 , 1.0};
GLfloat lightcolor[4] = {1.0 , 1.0 , 1.0 , 1.0};
GLfloat eyeposition[3] = {0.0 , 10.0 , 30.0};
GLfloat skycolor[3] = {0.7 , 0.7 , 1.0};
GLfloat groundcolor[3] = {0.2 , 0.2 , 0.2};
GLfloat Ns = 8;
GLfloat attenuation = 0.1;
GLfloat objectSize = 15.0;
GLuint program;
GLuint vShader , fShader;
GLApplication * GLApplication::Create(const char * class_name)
{
CGraphics * example = new CGraphics(class_name, "小练习-GLSL");
return reinterpret_cast<GLApplication *>(example);
}
CGraphics::~CGraphics(void)
{
}
CGraphics::CGraphics(const char * class_name,const char* form_title):GLApplication(class_name,form_title)
{
m_angle=0.0f;
}
bool CGraphics::Init()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
#pragma region 初始化glew
GLenum err=glewInit();
if(err!=GLEW_OK)
MessageBox(NULL,"failed to init glew!","提示",MB_OK);
#pragma endregion
#pragma region 读取顶点着色器和片源着色器源程序
const GLchar *vShaderSource = readShaderSource("vertexshader.txt");
const GLchar *fShaderSource = readShaderSource("fragmentshader.txt");
#pragma endregion
installShaders(vShaderSource,fShaderSource);
return true;
}
GLchar* CGraphics::readShaderSource(const char* filename)
{
GLchar *shader;
FILE *fp;
fp=fopen(filename,"rt+");
if(!fp)
MessageBox(NULL,"error","提示",MB_OK);
#pragma region 获取文件长度
rewind(fp);
fseek(fp,0,SEEK_END);
int len=ftell(fp);//返回当前文件指针的位置
#pragma endregion
rewind(fp); //回到文件开头
fseek(fp,0,SEEK_SET);
shader=(GLchar*)malloc(sizeof(char)*(len+1));
memset(shader,0,len+1);
fread(shader,sizeof(char),len,fp);
fclose(fp);
return shader;
}
int CGraphics::installShaders(const GLchar *Vertex, const GLchar *Fragment)
{
GLint vertCompiled, fragCompiled; // status values
GLint linked;
// Create a vertex shader object and a fragment shader object
vShader = glCreateShader(GL_VERTEX_SHADER);
fShader = glCreateShader(GL_FRAGMENT_SHADER);
// Load source code strings into shaders
glShaderSource(vShader, 1, (const char **)&Vertex, NULL);
glShaderSource(fShader, 1, (const char **)&Fragment, NULL);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(vShader);
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(fShader);
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
if (!vertCompiled || !fragCompiled)
MessageBox(NULL,"error","提示",MB_OK);
// Create a program object and attach the two compiled shaders
program = glCreateProgram();
glAttachShader(program, vShader);
glAttachShader(program, fShader);
// Link the program object and print out the info log
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked)
MessageBox(NULL,"error","提示",MB_OK);
#pragma region 编译信息,警告或错误(可以注释掉)
int infologlength;
int charswrriten;
char *infolog;
// Install program object as part of current state
glGetShaderiv(vShader,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
glGetShaderInfoLog(vShader,infologlength,&charswrriten,infolog);
MessageBox(NULL,infolog,"提示",MB_OK);
glGetShaderiv(fShader,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
glGetShaderInfoLog(fShader,infologlength,&charswrriten,infolog);
MessageBox(NULL,infolog,"提示",MB_OK);
#pragma endregion
//以上的代码被注释起来,作用是获得shader编译后的错误报告,用于调试,由于已经调试成功,这里就不需要这些代码了
return 1;
}
void CGraphics::Draw()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/*这里是程序比较重要的地方:向给shader中的uniform变量赋值。注意赋值函数使用的位置,只有当一个program启用的时候,里面的uniform变量才会被分配索引,所以过早的对uniform变量赋值会长生错误。同时注意函数的格式*/
glUseProgram(program);
glUniform3f(glGetUniformLocation(program , "lightposition") , 30.0 , 30.0 , 30.0);
glUniform3f(glGetUniformLocation(program , "eyeposition") , eyeposition[0] , eyeposition[1] , eyeposition[2]);
glUniform4f(glGetUniformLocation(program , "ambient") , ambient[0] , ambient[1] , ambient[2] , ambient[3]);
glUniform4f(glGetUniformLocation(program , "lightcolor") , lightcolor[0] , lightcolor[1] , lightcolor[2] , lightcolor[3]);
glUniform1f(glGetUniformLocation(program , "Ns") , Ns);
glUniform1f(glGetUniformLocation(program , "attenuation") , attenuation);
/*刚开始我以为要利用shader进行渲染就要必须将模型变为一个一个顶点信息向shader中传入,但其实并不是这样,我们同样可以利用glut的内建模型或者自己动手载入模型,和平时一样。同时注意一点,glut的一些内建模型只包含平面法线,没有纹理坐标,所以在后面我们给模型添加纹理的时候有些就无法显示出纹理*/
glPushMatrix();
glTranslatef(0.0f,0.0f,-50.0f);
glRotated(m_angle,0.0f,1.0f,0.0f);
glutSolidTeapot(objectSize);
glPopMatrix();
}
void CGraphics::Uninit()
{
}
void CGraphics::Update(DWORD milliseconds)
{
m_angle=m_angle+0.5f;
if (m_angle>=1440.0f)
{
m_angle=0.0f;
}
}
#include <gl\gl.h> /**< 包含OpenGL头文件 */
#include <gl\glu.h>
#include <gl\glaux.h>
GLfloat ambient[4] = {1.0 , 0.0 , 0.0 , 1.0};
GLfloat lightcolor[4] = {1.0 , 1.0 , 1.0 , 1.0};
GLfloat eyeposition[3] = {0.0 , 10.0 , 30.0};
GLfloat skycolor[3] = {0.7 , 0.7 , 1.0};
GLfloat groundcolor[3] = {0.2 , 0.2 , 0.2};
GLfloat Ns = 8;
GLfloat attenuation = 0.1;
GLfloat objectSize = 15.0;
GLuint program;
GLuint vShader , fShader;
GLApplication * GLApplication::Create(const char * class_name)
{
CGraphics * example = new CGraphics(class_name, "小练习-GLSL");
return reinterpret_cast<GLApplication *>(example);
}
CGraphics::~CGraphics(void)
{
}
CGraphics::CGraphics(const char * class_name,const char* form_title):GLApplication(class_name,form_title)
{
m_angle=0.0f;
}
bool CGraphics::Init()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
#pragma region 初始化glew
GLenum err=glewInit();
if(err!=GLEW_OK)
MessageBox(NULL,"failed to init glew!","提示",MB_OK);
#pragma endregion
#pragma region 读取顶点着色器和片源着色器源程序
const GLchar *vShaderSource = readShaderSource("vertexshader.txt");
const GLchar *fShaderSource = readShaderSource("fragmentshader.txt");
#pragma endregion
installShaders(vShaderSource,fShaderSource);
return true;
}
GLchar* CGraphics::readShaderSource(const char* filename)
{
GLchar *shader;
FILE *fp;
fp=fopen(filename,"rt+");
if(!fp)
MessageBox(NULL,"error","提示",MB_OK);
#pragma region 获取文件长度
rewind(fp);
fseek(fp,0,SEEK_END);
int len=ftell(fp);//返回当前文件指针的位置
#pragma endregion
rewind(fp); //回到文件开头
fseek(fp,0,SEEK_SET);
shader=(GLchar*)malloc(sizeof(char)*(len+1));
memset(shader,0,len+1);
fread(shader,sizeof(char),len,fp);
fclose(fp);
return shader;
}
int CGraphics::installShaders(const GLchar *Vertex, const GLchar *Fragment)
{
GLint vertCompiled, fragCompiled; // status values
GLint linked;
// Create a vertex shader object and a fragment shader object
vShader = glCreateShader(GL_VERTEX_SHADER);
fShader = glCreateShader(GL_FRAGMENT_SHADER);
// Load source code strings into shaders
glShaderSource(vShader, 1, (const char **)&Vertex, NULL);
glShaderSource(fShader, 1, (const char **)&Fragment, NULL);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(vShader);
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(fShader);
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
if (!vertCompiled || !fragCompiled)
MessageBox(NULL,"error","提示",MB_OK);
// Create a program object and attach the two compiled shaders
program = glCreateProgram();
glAttachShader(program, vShader);
glAttachShader(program, fShader);
// Link the program object and print out the info log
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked)
MessageBox(NULL,"error","提示",MB_OK);
#pragma region 编译信息,警告或错误(可以注释掉)
int infologlength;
int charswrriten;
char *infolog;
// Install program object as part of current state
glGetShaderiv(vShader,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
glGetShaderInfoLog(vShader,infologlength,&charswrriten,infolog);
MessageBox(NULL,infolog,"提示",MB_OK);
glGetShaderiv(fShader,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
glGetShaderInfoLog(fShader,infologlength,&charswrriten,infolog);
MessageBox(NULL,infolog,"提示",MB_OK);
#pragma endregion
//以上的代码被注释起来,作用是获得shader编译后的错误报告,用于调试,由于已经调试成功,这里就不需要这些代码了
return 1;
}
void CGraphics::Draw()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/*这里是程序比较重要的地方:向给shader中的uniform变量赋值。注意赋值函数使用的位置,只有当一个program启用的时候,里面的uniform变量才会被分配索引,所以过早的对uniform变量赋值会长生错误。同时注意函数的格式*/
glUseProgram(program);
glUniform3f(glGetUniformLocation(program , "lightposition") , 30.0 , 30.0 , 30.0);
glUniform3f(glGetUniformLocation(program , "eyeposition") , eyeposition[0] , eyeposition[1] , eyeposition[2]);
glUniform4f(glGetUniformLocation(program , "ambient") , ambient[0] , ambient[1] , ambient[2] , ambient[3]);
glUniform4f(glGetUniformLocation(program , "lightcolor") , lightcolor[0] , lightcolor[1] , lightcolor[2] , lightcolor[3]);
glUniform1f(glGetUniformLocation(program , "Ns") , Ns);
glUniform1f(glGetUniformLocation(program , "attenuation") , attenuation);
/*刚开始我以为要利用shader进行渲染就要必须将模型变为一个一个顶点信息向shader中传入,但其实并不是这样,我们同样可以利用glut的内建模型或者自己动手载入模型,和平时一样。同时注意一点,glut的一些内建模型只包含平面法线,没有纹理坐标,所以在后面我们给模型添加纹理的时候有些就无法显示出纹理*/
glPushMatrix();
glTranslatef(0.0f,0.0f,-50.0f);
glRotated(m_angle,0.0f,1.0f,0.0f);
glutSolidTeapot(objectSize);
glPopMatrix();
}
void CGraphics::Uninit()
{
}
void CGraphics::Update(DWORD milliseconds)
{
m_angle=m_angle+0.5f;
if (m_angle>=1440.0f)
{
m_angle=0.0f;
}
}