在片段着色器中我们可以使用方法discard来丢弃不想绘制出来的片段
比如下面的代码表示当一个片段的alpha值小于0.1时,就不绘制该片段
if(vColorValue.a < 0.1f)
{
discard;
}
本节我们写一个具有腐蚀效果的例子
如下图:
我们会看到,泳圈模型上有斑点,就像被腐蚀了一样
我们的代码和ADSPhone程序的代码差不多。只是使用了diacard方法而已
下面是具体的代码实现,基本上每一句话都有注释
下面是顶点着色器Dissolve.vp的全部的代码
// 要求OpenGL的版本最低是1.3
#version 130
// 需要从外界传入的字段
//顶点
in vec4 vVertex;
//顶点法线
in vec3 vNormal;
//纹理坐标
in vec2 vTexCoords0;
//模型视图变换矩阵
uniform mat4 mvpMatrix;
//视图变换矩阵
uniform mat4 mvMatrix;
//模型视图变换矩阵法线矩阵
uniform mat3 normalMatrix;
//光源的位置
uniform vec3 vLightPosition;
//需要传入片段着色器的字段
//面法线
smooth out vec3 vVaryingNormal;
//光源的方向
smooth out vec3 vVaryingLightDir;
//纹理坐标
smooth out vec2 vVaryingTexCoord;
void main(void)
{
//得到法线在照相机坐标系下的位置
vVaryingNormal = normalMatrix * vNormal;
// 得到顶点在照相机坐标系下的位置
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// 得到光源方向
vVaryingLightDir = normalize(vLightPosition - vPosition3);
// 得到纹理坐标
vVaryingTexCoord = vTexCoords0.st;
//把顶点变换到照相机坐标系下
gl_Position = mvpMatrix * vVertex;
}
下面是片段着色器Dissolve.fp的全部代码
// 要求OpenGL的版本最低是1.3
#version 130
//传出到光栅化阶段的颜色值
out vec4 vFragColor;
//环境光颜色值
uniform vec4 ambientColor;
//漫反射光颜色值
uniform vec4 diffuseColor;
//镜面光颜色值
uniform vec4 specularColor;
//需要使用的纹理对象
uniform sampler2D cloudTexture;
//腐蚀值
uniform float dissolveFactor;
//从顶点着色器传入的值
//面法线
smooth in vec3 vVaryingNormal;
//光源的方向
smooth in vec3 vVaryingLightDir;
//纹理坐标
smooth in vec2 vVaryingTexCoord;
void main(void)
{
vec4 vCloudSample = texture(cloudTexture, vVaryingTexCoord);
//判断是否丢弃片段
if(vCloudSample.r < dissolveFactor)
discard;
// 计算漫反射光强度
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// 漫反射光强度 乘上 漫反射光颜色值
vFragColor = diff * diffuseColor;
// 加上环境光颜色值
vFragColor += ambientColor;
// 乘上纹理颜色值
vFragColor *= vCloudSample;
// 加上镜面光颜色值
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
float fSpec = pow(spec, 128.0);
vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
}
}
下面是工程中的代码
首先我们来看一下需要包含的头文件和全局变量部分
#include <GLTools.h>
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#define FREEGLUT_STATIC
#include <GL/glut.h>
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
GLuint ADSDissloveShader;
//着色器uniform值
GLint locAmbient;
GLint locDiffuse;
GLint locSpecular;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
GLint locTexture;
GLint locDissolveFactor;
//纹理对象
GLuint cloudTexture;
下面是主函数main
int main(int argc, char* argv[])
{
//设置工程路径
gltSetWorkingDirectory(argv[0]);
//初始化GLUT
glutInit(&argc, argv);
//设置需要使用的窗口模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//窗口的大小
glutInitWindowSize(800, 600);
//窗口的名字
glutCreateWindow("Lit Texture");
//窗口大小改变时的回调函数
glutReshapeFunc(ChangeSize);
//渲染时的回调函数
glutDisplayFunc(RenderScene);
//初始化glew
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//初始化函数
SetupRC();
//消息循环
glutMainLoop();
//程序退出时的清理工作
ShutdownRC();
return 0;
}
下面是窗口大小改变时的回掉函数ChangeSize
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);
}
下面是初始化函数SetupRC
void SetupRC(void)
{
// Background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
glEnable(GL_DEPTH_TEST);
shaderManager.InitializeStockShaders();
viewFrame.MoveForward(4.0f);
// 生成小球模型数据
gltMakeTorus(torusBatch, .80f, 0.25f, 52, 26);
//加载自己写的着色器程序
ADSDissloveShader = gltLoadShaderPairWithAttributes("Dissolve.vp", "Dissolve.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords0");
//得到着色器中的uniform值的位置引用,以便对它赋值
locAmbient = glGetUniformLocation(ADSDissloveShader, "ambientColor");
locDiffuse = glGetUniformLocation(ADSDissloveShader, "diffuseColor");
locSpecular = glGetUniformLocation(ADSDissloveShader, "specularColor");
locLight = glGetUniformLocation(ADSDissloveShader, "vLightPosition");
locMVP = glGetUniformLocation(ADSDissloveShader, "mvpMatrix");
locMV = glGetUniformLocation(ADSDissloveShader, "mvMatrix");
locNM = glGetUniformLocation(ADSDissloveShader, "normalMatrix");
locTexture = glGetUniformLocation(ADSDissloveShader, "cloudTexture");
locDissolveFactor = glGetUniformLocation(ADSDissloveShader, "dissolveFactor");
//创建一个纹理对象
glGenTextures(1, &cloudTexture);
//绑定纹理对象
glBindTexture(GL_TEXTURE_1D, cloudTexture);
//加载纹理
LoadTGATexture("Clouds.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
下面是纹理加载函数LoadTGATexture
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);
//设置mip贴图
if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void RenderScene(void)
{
static CStopWatch rotTimer;
// Clear the window and the depth buffer
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.1f, 0.1f, 0.1f, 1.0f };
GLfloat vDiffuseColor[] = { 0.1f, 1.0f, 0.1f, 1.0f };
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//使用自己写的着色器
glUseProgram(ADSDissloveShader);
//设置着色器中的uniform值
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());
glUniform1i(locTexture, 1);
//在十秒之内 生成0-1的数值,然后赋值给locDissolveFactor
//GetElapsedSeconds函数表示自程序运行以来一共过去了多长时间
//fmod是一个求余函数 既x/y的余数
float fFactor = fmod(rotTimer.GetElapsedSeconds(), 10.0f);
fFactor /= 10.0f;
//设置统一值locDissolveFactor
glUniform1f(locDissolveFactor, fFactor);
//绘制模型
torusBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}