1. 着色器ADS光照,Phong着色,纹理的使用,Disssovle丢弃片段的例子
1. 客户端代码
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch sphereBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
GLuint ADSLightShader;
GLint locAmbient;
GLint locDiffuse;
GLint locSpecular;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
GLint locTexture;
GLuint locDissolve;
GLuint texture;
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) {
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//读取图片像素
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//设置纹理环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//设置纹理过滤模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//像素以非包装,每一个字节的方式进行存储
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//加载纹理
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//释放像素
free(pBits);
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//预加载纹理Mip贴图层,防止向前后移动几何体时上面的贴图加载过大,而出现性能消耗或者失真
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void SetupRC(void){
//设置背景颜色
glClearColor(0.0, 0.0, 0.0, 1.0);
//开启深度测试
glEnable(GL_DEPTH_TEST);
//剔除看不见的面,提高性能
glEnable(GL_CULL_FACE);
//初始化存储着色器
shaderManager.InitializeStockShaders();
//将角色帧向前移动
viewFrame.MoveForward(4.0);
//设置一个球体
gltMakeSphere(sphereBatch, 1.0, 26, 13);
//构建一个着色器
ADSLightShader = gltLoadShaderPairWithAttributes("ADSTexture.vp", "ADSTexture.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVtertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexture0");
//定位统一值得到统一值管理对象
locAmbient = glGetUniformLocation(ADSLightShader, "ambientColor");
locDiffuse = glGetUniformLocation(ADSLightShader, "diffuseColor");
locSpecular = glGetUniformLocation(ADSLightShader, "specularColor");
locLight = glGetUniformLocation(ADSLightShader, "vLightPosition");
locMVP = glGetUniformLocation(ADSLightShader, "mvpMatrix");
locMV = glGetUniformLocation(ADSLightShader, "mvMatrix");
locNM = glGetUniformLocation(ADSLightShader, "normalMatrix");
locTexture = glGetUniformLocation(ADSLightShader, "colorMap");
locDissolve = glGetUniformLocation(ADSLightShader, "dissolveFactor");
//设置纹理对象
glGenTextures(1, &texture);
//绑定纹理
glBindTexture(GL_TEXTURE_2D, texture);
//载入并设置纹理
LoadTGATexture("CoolTexture.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
void ShutdownRC(void){
//删除纹理对象
glDeleteTextures(1, &texture);
}
void RenderScene(void){
static CStopWatch rotTimer;
//清除颜色缓冲区和深度缓冲区数据
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//将角色帧对应的几何体和顶部的模型视图堆栈矩阵相乘放入模型视图堆栈的顶部
modelViewMatrix.PushMatrix(viewFrame);
//将堆栈中的角色帧旋转
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
//设置光线位置
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
//设置环境光颜色
GLfloat vAmbientColor[] = { 0.2f, 0.2f, 0.2f, 1.0f };
//设置漫射光颜色
GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f};
//设置反射光颜色
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//使用着色器程序
glUseProgram(ADSLightShader);
//设置环境光初始值
glUniform4fv(locAmbient, 1, vAmbientColor);
//设置漫射光初始值
glUniform4fv(locDiffuse, 1, vDiffuseColor);
//设置折射光初始值
glUniform4fv(locSpecular, 1, vSpecularColor);
//设置光源位置
glUniform3fv(locLight, 1, vEyeLight);
//设置模型视图投影矩阵
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
//设置模型视图矩阵
glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
//设置世界坐标系的几何表面法向矩阵
glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
//得到绑定的纹理对象
glBindTexture(GL_TEXTURE_2D, texture);
//设置纹理使用的Mip纹理贴图为基层
glUniform1i(locTexture, 0);
float fFactor = fmod(rotTimer.GetElapsedSeconds(), 20.0f);
fFactor /= 20.0f;
glUniform1f(locDissolve, fFactor);
// 绘制
sphereBatch.Draw();
// 角色帧出栈
modelViewMatrix.PopMatrix();
//双缓冲区交换数据
glutSwapBuffers();
//窗口刷新显示
glutPostRedisplay();
}
void ChangeSize(int w, int h){
if (h == 0){
h = 1;
}
//设置视口大小
glViewport(0, 0, w, h);
//设置投影锥体
viewFrustum.SetPerspective(35.0, float(w)/float(h), 1.0, 100.0);
//载入投影矩阵到投影堆栈
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//设置管线管理模型视图矩阵堆栈和投影矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Lit Texture");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
2. 着色器代码
//顶点着色器
//设置着色器版本
#version 120
//顶点着色器属性
attribute vec4 vVertex;
attribute vec3 vNormal;
attribute vec4 vTexture0;
//统一值
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
//下一阶段输出值
varying vec3 vVaryingNormal;
varying vec3 vVaryingLightDir;
varying vec2 vTexCoords;
void main(void) {
//得到视觉坐标系下的法向量
vVaryingNormal = normalMatrix * vNormal;
//得到视觉坐标系下的顶点
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//得到单位光源向量
vVaryingLightDir = normalize(vLightPosition - vPosition3);
//设置纹理坐标,纹理坐标会映射纹理单元的地址
vTexCoords = vTexture0.st;
// 对顶点进行模型视图投影变换计算
gl_Position = mvpMatrix * vVertex;
}
//片段着色器
//设置着色器版本号
#version 120
//统一值
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
uniform sampler2D colorMap;
uniform float dissolveFactor;
//上一阶段输入值
varying vec3 vVaryingNormal;
varying vec3 vVaryingLightDir;
varying vec2 vTexCoords;
//这里用到了Phong着色,只是向片段着色器传入没有插值颜色的顶点,因为插值颜色顶点是分布不均的,这样可能会出现光照不均的不想要的结果
//这里将颜色值作为统一值直接传给了片段着色器处理,代价是更多的性能消耗
void main(void) {
//通过纹理坐标找到需要贴图的几何体对应的纹理单元的纹理颜色值
vec4 vCloudSample = texture2D(colorMap, vTexCoords);
//当纹理单元的r值小于dissolveFactor时,舍弃该片段
if(vCloudSample.r < dissolveFactor)
discard;
// 得到法向量和光源向量的夹角,夹角的强度模拟漫射光在不同光源位置下的强度
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// 得到漫射光
gl_FragColor = diff * diffuseColor;
// 添加环境光
gl_FragColor += ambientColor;
// 这里先照亮纹理,因为纹理值乘以纯白色只会得到一个照亮的纹理值,不会表现出高光,然后在进行高光折射光的处理
//通过纹理坐标找到需要贴图的几何体对应的纹理单元的纹理颜色值通过相乘添加到之前的光源上得到新的光栅颜色值
gl_FragColor *= texture2D(colorMap, vTexCoords);
// 得到折射向量
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
// 得到反射光与法向量的夹角
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
//得到漫射光强度,其实OpenGL的照相机隐藏的做了视线的管理,反射光的强度是视觉向量和反射光向量的夹角值
float fSpec = pow(spec, 128.0);
//添加反射光
gl_FragColor.rgb += vec3(fSpec, fSpec, fSpec);
}
}
2. 纹理模拟光源
1. 客户端代码
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
GLuint toonShader;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
GLint locColorTable;
GLuint texture;
void SetupRC(void) {
//设置背景颜色
glClearColor(0.025f, 0.25f, 0.25f, 1.0f );
//开启深度测试,防止图元重叠
glEnable(GL_DEPTH_TEST);
//开启图元剔除,剔除看不见的图元提高性能
glEnable(GL_CULL_FACE);
//初始化存储着色器
shaderManager.InitializeStockShaders();
//角色帧向前移动
viewFrame.MoveForward(4.0f);
//设置花托,通过torusBatch容器管理
gltMakeTorus(torusBatch, 0.80f, 0.25f, 52, 26);
//生成着色器程序
toonShader = gltLoadShaderPairWithAttributes("ToonShader.vp", "ToonShader.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
//定位统一值,得到统一值管理对象
locLight = glGetUniformLocation(toonShader, "vLightPosition");
locMVP = glGetUniformLocation(toonShader, "mvpMatrix");
locMV = glGetUniformLocation(toonShader, "mvMatrix");
locNM = glGetUniformLocation(toonShader, "normalMatrix");
locColorTable = glGetUniformLocation(toonShader, "colorTable");
//设置纹理对象
glGenTextures(1, &texture);
//绑定纹理
glBindTexture(GL_TEXTURE_1D, texture);
//设置一维纹理对应的像素数据(RGB),一维纹理的坐标大于0小于1,通过一维纹理坐标会映射到纹理地址,着色器会通过法向量和光源向量夹角来表示一维纹理坐标来模拟漫射光强度,
GLubyte textureData[4][3] = { 32, 0, 0,
64, 0, 0,
128, 0, 0,
255, 0, 0};
//载入纹理,一维纹理,当前层为基层,压缩方式为rgb,长度是4,边框为0,纹理数据为无符号,像素是textureData
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);
//设置纹理过滤方式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//设置纹理环绕模式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//预加载纹理Mip贴图层,防止向前后移动几何体时上面的贴图加载过大,而出现性能消耗或者失真
glGenerateMipmap(GL_TEXTURE_1D);
}
void ShutdownRC(void) {
//清理纹理对象
glDeleteTextures(1, &texture);
}
// Called to draw scene
void RenderScene(void) {
static CStopWatch rotTimer;
//清除颜色缓冲区数据,清除深度缓冲区数据和
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//将角色帧对应的几何体的顶点和顶部的模型视图矩阵堆栈矩阵相乘放入模型视图矩阵堆栈的顶部
modelViewMatrix.PushMatrix(viewFrame);
//模型视图变换,旋转变换
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
//设置光线位置
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
//使用着色器程序
glUseProgram(toonShader);
//设置着色器统一值
glUniform3fv(locLight, 1, vEyeLight);
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
glUniform1i(locColorTable, 0);
//绘制
torusBatch.Draw();
//移出模型视图堆栈底部的矩阵
modelViewMatrix.PopMatrix();
//交换前后台缓冲区数据
glutSwapBuffers();
//刷新展示
glutPostRedisplay();
}
void ChangeSize(int w, int h) {
if(h == 0){
h = 1;
}
//设置视口
glViewport(0, 0, w, h);
//设置投影变换
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
//载入投影矩阵到投影矩阵堆栈
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//设置管线管理模型视图矩阵堆栈和投影矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
int main(int argc, char* argv[]) {
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Cell (toon) shading");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
2. 着色器代码
//顶点着色器
//设置着色器版本
#version 120
//设置顶点着色器属性
attribute vec4 vVertex;
attribute vec3 vNormal;
//下一阶段输出值
varying float textureCoordinate;
//统一值
uniform vec3 vLightPosition;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
void main(void) {
//设置视觉坐标系下的单位法向量
vec3 vEyeNormal = normalMatrix * vNormal;
//设置视觉坐标系下的顶点值
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//设置光源向量
vec3 vLightDir = normalize(vLightPosition - vPosition3);
//得到法向量与光线向量的夹角,这个值作为片段着色器一维纹理的寻址坐标
//一维纹理单元坐标是大于0小于1的会映射到一维纹理单元的地址,正好可用夹角值模拟
textureCoordinate = max(0.0, dot(vEyeNormal, vLightDir));
//对顶点进行模型视图投影矩阵变换计算
gl_Position = mvpMatrix * vVertex;
}
//片段着色器
//着色器版本
#version 120
//统一值
uniform sampler1D colorTable;
//上一阶段输出值
varying float textureCoordinate;
void main(void) {
//通过纹理坐标找到纹理单元得到纹理颜色值
//对纹理颜色光栅化
gl_FragColor = texture1D(colorTable, textureCoordinate);
}